package com.foreveross.crawl.adapter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.net.URLClassLoader;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.foreveross.crawl.common.ChannelProperties;
import com.foreveross.crawl.common.db.JdbcProperties;
import com.foreveross.crawl.common.util.ClassLoadUtils;
import com.foreveross.taskservice.common.bean.TaskModel;

/**
 * 一个提供适配器的玩意，包含了一个自动去检测后台有没有更新adapter的线程
 * 
 * @author guokenye
 *
 */
public class AdapterManager {
	private static Logger logger=LoggerFactory.getLogger(AdapterManager.class);
	private static AdapterManager manager;
	private static URLClassLoader loader = null;
	private static Properties channelProperties = null;
	private static Properties jdbcProperties = null;
	
	static {
		try {
			loadConfig();
			update(true);
			/**
			 * 定时检测更新的线程
			 */
//			new Thread(new Runnable() {
//				
//				@Override
//				public void run() {
//					while(true){
//						try {
//							Thread.sleep(AdapterInfo.getUpdateInterval());
//							logger.info(String.format("开始检测适配器版本信息！"));
//							//update(false);
//							logger.info(String.format("适配器检查完毕！"));
//						} catch (Exception e) {
//							logger.error(e.getMessage());
//						}
//					}
//				}
//			}).start();
		} catch (Exception e) {
			logger.error(e.getMessage());
		}finally {
			
		}
	}
	
	private AdapterManager() {}
	
	protected static AdapterManager getInstance(){
		if(manager==null){
			manager=new AdapterManager();
		}
		return manager;
	}
	
	private  static void loadConfig(){
		ChannelProperties c ;
		JdbcProperties j;
		try{
			logger.info("开始加载配置文件！");
			c = new ChannelProperties();
			c.load();
			channelProperties = c.getProp();
			j = new JdbcProperties();
			j.load();
			jdbcProperties = j.getProp();
			Class.forName(jdbcProperties.getProperty("jdbc.driverClassName"));
			logger.info("加载配置完毕！");
		}catch(Exception e){
			logger.error(e.getMessage());
		}finally{
			c=null;j=null;
		}
	}
	
	private static void update(boolean isFirst) {
		File tmp ;
		File[] pathFiles;
		try{
			tmp = new File(AdapterInfo.getAdapterClassSavePath());
			if(!tmp.exists())
				tmp.mkdirs();
			pathFiles = tmp.listFiles();
			boolean flag=getClassFile(pathFiles, AdapterInfo.getAdapterClassSavePath());
			if(isFirst || flag){
				ClassLoadUtils.add(AdapterInfo.getAdapterClassReadPath());
				loader = ClassLoadUtils.getClassLoader(null);
				logger.info("ClassLoader 重载完毕!");
			}
		}catch(Exception e){
			logger.error(e.getMessage());
		}finally{
			tmp=null;pathFiles=null;
		}
	}
	
	
	/**
	 * 提供一个方法供别人获得一个适配器
	 * @param id
	 * @param qlog
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected  AbstractAviationAdapter buildAdapter(Long id,TaskModel qlog) throws Exception{
		Object className;
		Class c;
		Constructor constructor;
		
		try {
			className= channelProperties.get(String.valueOf(id));
			if(className==null){
				return new DefaultAdapter(qlog);
			}else{
				c = loader.loadClass(AdapterInfo.getPackPath()+"."+ className);
				constructor= c.getConstructor(TaskModel.class);
				return (AbstractAviationAdapter) constructor.newInstance(qlog);
			}
		}finally{
			className=null;
			c=null;
			constructor=null;
		}
		
	}
	
	
	/**
	 * 下载
	 * 这里下载的逻辑是 ：先去表 fdc_task_adapter 找出所有 isEnable=1 的所有适配器文件id，然后去 FDC_TASK_ADAPTER_UPLOADED 根据id下载文件即可！
	 * 之前isEnable字段被定义为varchar，所以只能用='1'以后再优化
	 * 当新下载了文件之后需要重新加载，返回true
	 * @param pathFiles
	 * @param adapterClassPath
	 * @throws Exception
	 */
	private static boolean getClassFile(File[] pathFiles,String adapterClassPath) throws Exception   {
		return false;
		/*
		return false;
		  
		boolean isReLoad=false;
		Connection connection=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		String sql=null;
		String className=null;
		byte[] buffer=null;
		int classSize;
		InputStream is=null;
		boolean flag;
	    try {
	    	sql="select * from FDC_TASK_ADAPTER_UPLOADED u" +
	    			" where u.ID in"+
	    			" (select ADAPTER_UPLOAD_ID from FDC_TASK_ADAPTER t where t.ISENABLE='1')";
	    	buffer = new byte[4096];
	    	connection = DriverManager
					.getConnection(jdbcProperties.getProperty("jdbc.url"),
							jdbcProperties.getProperty("jdbc.username"), jdbcProperties.getProperty("jdbc.password"));
			ps=connection.prepareStatement(sql);  
			rs = ps.executeQuery();  
			while(rs.next()){
				className = rs.getString("CLASS_NAME");
				classSize = rs.getInt("CLASS_SIZE");
				is = rs.getBinaryStream("ADAPTER_DATA");
				if(pathFiles.length > 0){
					flag = Boolean.FALSE;
					for (int i = 0; i < pathFiles.length; i++) {
						//如果数据库中的class名在本地class库中存在 且文件大小一致
						//还要判断本地和数据库文件大小是否一致
						if(className.equals(pathFiles[i].getName())&&classSize==pathFiles[i].length()){
							flag = Boolean.TRUE;
							break;
						}
					}
					if(!flag){
						writeFile(is, new File(adapterClassPath+File.separator+className), buffer);
						isReLoad=true;
						logger.info(String.format("从数据库下载适配器文件[%s]", className));
					}else{
						logger.info(String.format("适配器文件 [%s] 与数据库一致,无需下载", className));
					}
				}else{
					writeFile(is, new File(adapterClassPath+File.separator+className), buffer);
					isReLoad=true;
					logger.info(String.format("从数据库下载适配器文件[%s]", className));
				}
			}
		} catch (Exception e) {
			logger.info(e.getMessage());
		} finally{
			if(is!=null){is.close();is=null;}
			if(rs!=null){rs.close();rs=null;}
			if(ps!=null){ps.close();ps=null;}
			if(connection!=null){connection.close();connection=null;}
			sql=null;
			buffer=null;
			className=null;
		}
	    return isReLoad;
	*/}  
	
	
	private static void writeFile(InputStream is,File file,byte[] buffer) throws Exception{
		FileOutputStream outputStream = null;
		int size;  
		try {
			if(!file.exists()){ file.createNewFile(); }
			outputStream = new FileOutputStream(file);  
			size=0;
			while((size=is.read(buffer))!=-1){  
			    outputStream.write(buffer,0,size);  
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}finally{
			if(outputStream!=null){outputStream.close();outputStream=null;}
		}
	}
	
	
	
	
	public static void main(String[] args) throws Exception {
		AbstractAviationAdapter adapter=AdapterManager.getInstance().buildAdapter(2l, new TaskModel());
		System.out.println(adapter);
	}
}
